﻿/*****
* 系统客户端全局配置文件
*/

var _config_ = new function () {
    'use strict';
    var that = this;

    this.default = {
        placeholder: '-',
        pluginNamespacePrefix: 'devonline.plugin',
        parameterPrefix: 'parameterPrefix',
        parameterPrefixValue: '#:',
        arrayTypeName: 'array',
        kendoValidator: 'kendoValidator',
        kendoValidatorPlugin: 'jQuery.fn.kendoValidator',
        layout: 'horizontal',
        ignoreFields: '@odata.etag,serial,uid,dirty,removable',
        attachmentPath: '/api/Attachments/Files/',
        dataState: {
            available: 'Available',
            unavailable: 'Unavailable',
            frozen: 'Frozen',
            updated: 'Updated',
            deleted: 'Deleted',
            obsoleted: 'Obsoleted',
            destroyed: 'Destroyed'
        }
    };

    this.attribute = {
        serial: 'data-serial',
        id: 'data-id',
        parameterPrefix: 'data-parameter-prefix',
        parameterArg: 'data-parameter-arg',
        parameterArgNode: 'node',
        parameterArgNodeType: 'node-type',
        required: 'required',
        plugin: 'data-toggle',
        field: 'data-field',
        fieldset: 'data-fieldset',
        button: 'data-button',
        queryButton: 'data-button="query"',
        form: 'data-toggle="form"',
        formArray: 'data-type="array"',
        formAttr: 'data-form',
        grid: 'data-toggle="grid"',
        popup: 'data-popup',
        popupWindow: 'data-toggle="popup"',
        tooltip: 'data-toggle="tooltip"',
        uploaderAttachment: 'data-attachment',
        maxLength: 'data-max-length',
        minLength: 'data-min-length',
        inputInvalidMsg: 'k-invalid-msg"',
        namedPrefix: 'named-prefix',
        dataNamedPrefix: 'data-named-prefix',
        autoStartup: 'data-auto-startup',
        popupParameter: 'data-popup-parameter',
        openerProperty: 'data-opener-property'
    };

    this.selector = {
        'default': 'xxxxx',
        serial: '[data-serial]',
        id: '[data-id]',
        required: '[required]',
        plugin: '[data-toggle]',
        field: '[data-field]',
        fieldset: '[data-fieldset]',
        button: '[data-button]',
        form: '[data-toggle="form"][data-field]',
        formArray: '[data-toggle="form"][data-type="array"][data-field]',
        formAttr: '[data-form]',
        grid: '[data-toggle="grid"]',
        popup: '[data-popup]',
        popupWindow: '[data-toggle="popup"]',
        tooltip: '[data-toggle="tooltip"]',
        //notForm: '[data-toggle="grid"],[data-toggle="popup"],[node]',
        notForm: '[data-toggle="grid"],[node]',
        postButton: '[data-button="post"]',
        putButton: '[data-button="put"]',
        deleteButton: '[data-button="delete"]',
        queryButton: '[data-button="query"]',
        okButton: '[data-button="ok"]',
        closeButton: '[data-button="close"]',
        addButton: '[data-button="add"]',
        editButton: '[data-button="edit"]',
        enterPressButton: '[data-button][data-enter-press="true"]',
        uploaderAttachment: '[data-attachment]',
        inputFormGroup: '.form-group',
        inputInvalidMsg: '.k-invalid-msg',
        maxLength: '[data-max-length]',
        minLength: '[data-min-length]',
        namedPrefix: '[named-prefix],[data-named-prefix]',
        autoStartup: '[data-auto-startup]',
        showbox: '[data-toggle="showbox"]',
        popupParameter: '[data-popup-parameter]',
        openerProperty: '[data-opener-property]'
    };

    this.dataSource = {
        defaults: {
            type: 'odata-v4',
            autoQuery: false,
            serverFiltering: true,
            serverSorting: true,
            serverPaging: true,
            pageSize: 10
        },
        noPaging: {
            type: 'odata-v4',
            autoQuery: false,
            serverFiltering: true,
            serverSorting: true,
            serverPaging: false,
            pageSize: 999999
        },
        grid: {
            type: 'odata-v4',
            autoQuery: true,        //是否在初始化阶段开始自动查询
            serverFiltering: true,
            serverSorting: true,
            serverPaging: true,
            pageSize: 10,
            sort: {
                field: "UpdatedOn", dir: "desc"
            },
            schema: {
                model: {
                    fields: {}
                },
                parse: function (response) {
                    response = $.com.odataAdapter(response);
                    if ($.com.hasValue(response) && $.com.isArray(response.value) && $.com.isArray(this.navigationColumns)) {
                        for (var i = 0; i < response.value.length; i++) {
                            var data = response.value[i];
                            for (var j = 0; j < this.navigationColumns.length; j++) {
                                var column = this.navigationColumns[j];
                                var key = column.field;
                                var value = $.com.getValue(data, key);
                                if (!$.com.hasValue(value)) {
                                    //key = key.replace(/\[\d+\]/, '');
                                    $.com.setValue(data, key, '');
                                }
                                if ($.com.hasValue(value) && (column.type === 'date' || column.type === 'time' || column.type === 'datetime')) {
                                    value = new Date(value);
                                    $.com.setValue(data, key, value);
                                }
                            }
                        }
                    }

                    return response;
                }
            },
            requestStart: function (e) {
                if (e && !e.sender.options.autoQuery) {
                    e.preventDefault();
                }
            }
        }
    };

    this.field = {
        namespace: 'devonline.plugin.field',
        defaults: {
            field: undefined,
            type: 'text',
            title: undefined,
            label: undefined,
            value: undefined,
            valueFrom: undefined,                               //value 值来自某个字段, 如果值不为空则, value 值不取 field 字段而取 value from 的值
            role: undefined,                                    //*****组件可用性级别, 分以下4种, 但是如果组件属性跟role定义的组件属性冲突, 优先以role定义为主: 
            enable: true,                                       //enable: 可用(可编辑, 可触发事件, 反之均不能)
            editable: true,                                     //editable: 可编辑(指可输入或选择, 但不可触发事件)
            readonly: false,                                    //readonly: 只读(不可编辑, 但可触发事件)
            display: true,                                      //display: 可见(不可见状态不能人为触发事件, 仅能通过脚本触发)
            withGroup: false,
            inline: true,                                       //withGroup=true 且 inline=true 则使用内联样式, 即内部块横排布局, 否则都按竖排布局
            unique: false,
            message: undefined,
            valid: undefined,                                   //undefined, true, false
            side: 'client',
            url: undefined,
            data: undefined,
            alwaysInitial: false,                               //始终使用初始值
            initialWhenEmpty: true,                             //当value值为空值时使用初始值
            validateWhenDisplay: false,                         //可见则验证, 即仅元素可见时验证, 默认 false, 设置为 true, 则隐藏时不验证

            //布局选项
            template: '#__TemplateField',                       //布局模版
            fieldset: true,                                     //是否使用布局
            layout: 'horizontal',                               //布局方式, 水平: horizontal, 垂直: vertical
            size: '12,3,8',                                     //布局尺寸: <整体宽度, 标签宽度, 表单元素宽度>, 默认: 垂直布局(3, 12, 12), 水平布局(3, 3, 9)
            required: false,                                    //是否必填
            icon: undefined,                                    //图标样式: 自定义
            iconTemplate: '#__TemplateIcon',                    //图标模板
            tooltip: false,                                     //使用tooltips
            tooltipIcon: 'glyphicon glyphicon-question-sign',   //tooltip图标样式
            tooltipPlacement: 'right',                          //tooltip位置
            tooltipTitle: undefined,                            //tooltip文字

            //filter 扩展选项
            dataType: 'string',
            logic: 'and',
            operator: 'eq',
            filters: undefined,
            autoQuery: false,                                   //用于在自动匹配框获得焦点时自动触发查询

            //通用数据绑定选项
            dataValueField: 'Key',
            dataTextField: 'Text',

            //dropdownlist 扩展选项
            optionLabel: '---请选择---',
            selectedValue: undefined,

            single: false,                                      //是否单一文件上传, 单一文件上传情况比较特殊, 默认使用了基类名叫 Attachments 的共享集合保存附件, 因此需要根据 businessType 的值区分字段值
            dataKeyField: 'Id',                                 //当前表单绑定的对象的数据主键字段
            withAttachments: false,                             //是否有附件, 如果有, 则会根据当前 form data dataKeyField 指定列查出已有附件, 并绑定到当前列上, 如果 withAttachments 指定了列名, 则使用 withAttachments 指定名字的集合
            businessType: undefined,

            //popup 扩展选项
            popup: undefined,
            opener: undefined,
            parameter: undefined,
            target: undefined,

            //field 联动
            next: undefined,                                    //联动的下一个元素

            loading: undefined,
            loaded: undefined,
            binding: undefined,
            bound: undefined,
            clicking: undefined,
            clicked: undefined,
            changing: undefined,
            changed: undefined,
            selecting: undefined,
            selected: undefined,
            keyPressing: undefined,
            keyPressed: undefined,
            querying: undefined,
            queried: undefined,
            focusing: undefined,
            focused: undefined,
            iconClicking: undefined,
            iconClicked: undefined,
            dataAdapter: $.com.dataAdapter,
            formatter: undefined,
            validator: undefined
        },
        methods: [
            'init',
            'reInit',
            'getData',
            'getValue',
            'setValue',
            'readonly',
            'display',
            'clear',
            'reset',
            'refresh',
            'writeBack',
            'getQueryExpression',
            'getFormData',
            'validate',
            'destroy'
        ],
        events: [
            'click',
            'change',
            'blur',
            'select',
            'query',
            'iconClick'
        ],
        /*
         * kendo 组件赋值本地数据源需指定到 dataSource 字段
         */
        initials: {
            dataType: 'string',
            logic: 'and',
            operator: 'eq',
            role: 'textbox',
            dataValueField: 'Key',
            dataTextField: 'Text',
            optionLabel: '---请选择---',
            noDataTemplate: '无数据显示',
            dataSource: this.dataSource.defaults
        }
    };

    this.button = {
        namespace: 'devonline.plugin.button',
        defaults: {
            button: undefined,
            action: undefined,
            icon: undefined,
            type: 'POST',
            dataType: 'json',
            label: undefined,
            textField: 'Id',
            valueField: 'Id',
            role: undefined,                //*****组件可用性级别, 分以下4种, 但是如果组件属性跟role定义的组件属性冲突, 优先以role定义为主: 
            enable: true,                   //enable: 可用(可编辑, 可触发事件, 反之均不能)
            editable: false,                //editable: 可编辑(指可输入或选择, 但不可触发事件)
            readonly: true,                 //readonly: 只读(不可编辑, 但可触发事件)
            display: true,                  //display: 可见(不可见状态不能人为触发事件, 仅能通过脚本触发)
            side: 'server',
            url: undefined,
            actionById: true,               //服务器接口默认的处理方式是 action by id, 指 put 和 delete 等方法 url 中需要名为 key 的参数, 以及 body 的值, 默认为 true; 设置 false 则认为服务器需要传递当前对象作为参数来, 适用于自动处理
            keepReference: true,            //是否保留对象引用, 适用于提交服务器之前, 调用 cleanData 的参数
            template: '#__TemplateButton',
            withGroup: false,
            enterPress: false,              //默认不响应回车, 如果设置为 true, 则会在 form 范围内按下回车键时触发
            confirm: false,                 //确认, 事件触发前, 是否先弹出确认一次?
            confirmTitle: '请确认',
            confirmText: '请确认是否要执行当前操作?',
            prompt: false,                  //弹出提示, 事件完成后, 是否弹出提示
            successTitle: '',
            successText: '保存成功!',
            errorTitle: '',
            errorText: '保存失败!',
            authorize: false,               //按钮是否要经过授权
            authorizeLogic: 'or',           //functionid 和 authorizeMethod 条件的授权逻辑 and or
            functionid: undefined,          //授权的functionId, 多个以逗号隔开
            authorizeMethod: undefined,     //授权方式
            isAuthenticated: undefined,     //指示组件是否已通过授权认证

            style: 'popup',                 //针对高级查询区域的显示方式, 默认 popup, 可选方式还有 dropdown
            autoShrink: false,              //针对高级查询区域的收缩方式, 点击查询事件后, 是否自动收缩查询区域

            loading: undefined,
            loaded: undefined,
            clicking: undefined,
            clicked: undefined,
            beforeSubmit: undefined,
            beforeSend: undefined,
            success: undefined,
            error: undefined,
            complete: undefined
        },
        methods: [
            'init',
            'getData',
            'getValue',
            'setValue',
            'display',
            'destroy'
        ],
        events: [
            'click'
        ],
        Actions: {
            'default': { name: 'default', action: undefined, 'class': "btn-default" },
            //确定按钮
            ok: { name: 'ok', action: undefined, 'class': "btn-primary", icon: 'fa fa-check' },
            //关闭按钮
            close: { name: 'close', action: undefined, 'class': "btn-default", icon: 'fa fa-times' },
            remove: { name: 'remove', action: undefined, 'class': "btn-danger", icon: 'fa fa-times' },
            print: { name: 'print', action: undefined, 'class': "btn-danger", icon: 'fa fa-print' },
            showbox: { name: 'showbox', action: undefined, 'class': undefined, icon: undefined },

            noiconLink: { name: 'noiconLink', action: 'onLink', 'class': "btn-primary" },
            add: { name: 'add', action: 'onLink', 'class': "btn-primary", icon: 'fa fa-plus' },
            edit: { name: 'edit', action: 'onLink', 'class': "btn-purple", icon: 'fa fa-edit' },
            link: { name: 'link', action: 'onLink', 'class': "btn-default", icon: 'fa fa-link' },
            back: { name: 'back', action: 'onLink', 'class': "btn-default", icon: 'fa fa-chevron-left' },
            approved: { name: 'approved', action: 'onApproved,onSubmit', 'class': "btn-success", icon: 'fa fa-check' },
            reject: { name: 'reject', action: 'onReject,onSubmit', 'class': "btn-warning", icon: 'fa fa-warning' },
            termination: { name: 'termination', action: '', 'class': "btn-primary", icon: 'fa fa-stop' },
            detail: { name: 'detail', action: 'onLink', 'class': "btn-success", icon: 'fa fa-eye' },

            clear: { name: 'clear', action: 'onClear', 'class': "btn-default", icon: 'fa fa-times' },
            reset: { name: 'reset', action: 'onReset', 'class': "btn-default", icon: 'fa fa-undo' },
            query: { name: 'query', action: 'onQuery', 'class': "btn-primary", icon: 'fa fa-search', enterPress: true },
            clearAndQuery: { name: 'clearAndQuery', action: 'onClear,onQuery', 'class': "btn-default", icon: 'fa fa-times' },
            resetAndQuery: { name: 'resetAndQuery', action: 'onReset,onQuery', 'class': "btn-default", icon: 'fa fa-undo' },
            //高级查询按钮
            advancedSearch: { name: 'advancedSearch', action: 'onAdvancedSearch', 'class': "", style: "popup" },

            'import': {
                name: 'import', action: 'onImport', 'class': 'btn-primary', icon: 'fa fa-cloud-upload',
                template: '#__TemplateUpload',
                type: 'post',
                prompt: false,
                success: function (el, data, xhr) {
                    if ($.com.hasValue(data)) {
                        var $popup = $('[data-toggle="popup"][data-type="ImportView"]');
                        if ($popup.hasValue()) {
                            $popup.trigger('open', $.extend({
                                title: '导入预览',
                                opener: el.$el,
                                confirming: el.options.confirming,
                                confirmed: el.options.confirmed
                            }, that.popupWindow.size.importView));
                            var popup = $popup.data(that.popupWindow.namespace);
                            if ($.com.hasValue(popup) && popup.$grid.hasValue()) {
                                var grid = popup.$grid.data(that.grid.namespace);
                                if (!$.com.hasValue(grid) || !$.com.hasValue(grid.role)) {
                                    popup.$grid.grid();
                                    grid = popup.$grid.data(that.grid.namespace);
                                }

                                if ($.com.hasValue(grid) && $.com.hasValue(grid.role)) {
                                    var options = {};
                                    var columns = [];
                                    if ($.com.isArray(data)) {
                                        //返回DataTable的形式
                                        for (var i = 0; i < data.length; i++) {
                                            $.each(data[i], function (k, v) {
                                                var f = k.replace(/[\(|\)]/g, '_');
                                                if (i === 0) {
                                                    columns.push({ title: k, field: f, attributes: { 'class': 'popup' } });
                                                }
                                            });
                                        }

                                        options = { columns: columns, dataSource: data };
                                    } else if ($.com.isArray(data.Header) && $.com.isArray(data.Body)) {
                                        //返回ExcelEntitySet的形式
                                        if ($.com.isArray(data.Header)) {
                                            for (var i = 0; i < data.Header.length; i++) {
                                                data.Header[i].attributes = { 'class': 'popup' };
                                            }
                                        }

                                        options = { columns: data.Header, dataSource: data.Body };
                                    }

                                    if ($.com.isArray(options.columns)) {
                                        options.columns.insert(that.grid.rowIndex, 0);
                                    }
                                    grid.role.setOptions(options);
                                    grid.resize();
                                    popup.$grid.show();
                                    popup.$buttons.filter('[data-button="determine"]').show();
                                    popup.$el.find('.import-error').hide();
                                }
                            }
                        }
                    }
                },
                error: function (el, xhr) {
                    if ($.com.hasValue(xhr)) {
                        var msg = $.com.getValue(xhr, 'responseJSON.ExceptionMessage') || xhr.responseText || '';
                        var $popup = $('[data-toggle="popup"][data-type="ImportView"]');
                        if ($popup.hasValue()) {
                            $popup.trigger('open', $.extend({ title: '导入错误!' }, that.popupWindow.size.importView));
                            var popup = $popup.data(that.popupWindow.namespace);
                            if ($.com.hasValue(popup)) {
                                popup.$grid.hide();
                                //var grid = popup.$grid.data(that.grid.namespace);
                                //if ($.com.hasValue(grid)) {
                                //    grid.destroy();
                                //}

                                popup.$buttons.filter('[data-button="determine"]').hide();
                                popup.$el.find('.import-error').show().html(msg);
                            }
                        }
                    }
                }
            },
            'export': { name: 'export', action: 'onExport', 'class': 'btn-primary', icon: 'fa fa-cloud-download' },
            upload: { name: 'upload', action: 'onUpload', 'class': 'btn-default', icon: 'fa fa-upload', template: '#__TemplateUpload' },
            download: { name: 'download', action: 'onDownload', 'class': 'btn-default', icon: 'fa fa-download' },
            addForm: { name: 'addForm', action: 'onAddForm', 'class': "btn-primary", icon: 'fa fa-plus' },
            removeForm: { name: 'removeFrom', action: 'onRemoveForm', 'class': "btn-default", icon: 'fa fa-times' },

            get: { name: 'get', action: 'onSubmit', 'class': "btn-default", icon: 'fa fa-search', type: 'GET' },
            post: { name: 'post', action: 'onSubmit', 'class': "btn-success", icon: 'fa fa-file-text', type: 'POST' },
            put: { name: 'put', action: 'onSubmit', 'class': "btn-purple", icon: 'fa fa-file-text', type: 'PUT' },
            'delete': { name: 'delete', action: 'onSubmit', 'class': "btn-danger", icon: 'fa fa-trash', type: 'DELETE', confirm: true, confirmText: '确认要删除吗?', prompt: true, successText: '删除成功!', errorText: '删除失败!' },
            save: { name: 'save', action: 'onSubmit', 'class': "btn-primary", icon: 'fa fa fa-save', prompt: true },
            submit: { name: 'submit', action: 'onSubmit', 'class': "btn-purple", icon: 'fa fa-check' }
        }
    };

    this.form = {
        namespace: 'devonline.plugin.form',
        defaults: {
            //properties
            type: 'form',
            readonly: undefined,
            display: true,
            valid: true,                    //undefined, true, false
            url: undefined,
            side: 'client',
            httpMethod: 'get',
            data: undefined,
            dataSource: undefined,
            autoStartup: false,             //是否自动初始化
            alwaysInitial: false,           //始终使用初始值

            detailable: false,              //详情状态, 用于标记表单是否处于可编辑模式, true 则为详情状态, 整个表单用不可编辑的组件绘制. false, 则使表单切换到 editable 模式
            editable: false,                //可编辑状态, 用于标记表单是否处于编辑状态, false 则为新增状态. 正常情况下表单是新增和编辑状态共享的
            removable: true,                //是否删除一个 form 可选值： true(物理删除, 同时删除元素和数据), false(逻辑删除, 既不删除元素也不删除数据, 只标记数据状态为 Deleted, 表示已处于被删除状态, 再次删除则可直接删掉)
            filterable: false,              //可查询状态, 标记一个 form 是用于 grid 上的查询区, 查询区的 form 需要设置该标记为 true 的值

            autoDraw: false,                //是否自动绘制子组件
            drawPlacement: 'append',        //自动绘制位置在最前, append 则会绘制到末尾位置, 否则认为为 prepend, 则会绘制到起始位置, 其余位置则需自定义
            template: undefined,            //自动绘制子组件使用的模板
            validateWhenDisplay: false,     //可见则验证, 即仅元素可见时验证, 默认 false, 设置为 true, 则隐藏时不验证
            autoRefreshLayout: true,        //是否在子 form 增删之后自动刷新布局样式
            dataKeyField: 'Id',             //当前表单绑定的对象的数据主键字段
            dataKeyType: 'string',          //当前表单绑定的对象的数据主键数据类型
            dataStateField: 'State',        //当前表单绑定的对象的数据状态字段
            dataOrderByField: 'Index',      //当前表单绑定的对象的数据排序字段
            ignoreFields: undefined,        //当前表单提交时忽略的字段名

            //methods
            dataAdapter: $.com.dataAdapter,
            loading: undefined,
            loaded: undefined,
            binding: undefined,
            bound: undefined,
            changing: undefined,
            changed: undefined,
            validator: undefined,           //kendo ui validator elements
            validate: undefined             //custom validate
        },
        methods: [
            'init',
            'reInit',
            'getData',
            'getValue',
            'setValue',
            'readonly',
            'display',
            'clear',
            'reset',
            'refresh',
            'addForm',
            'removeForm',
            'refreshForm',
            'refreshLayout',
            'writeBack',
            'getFormData',
            'getQueryExpression',
            'validate',
            'destroy'
        ],
        events: []
    };

    this.grid = {
        namespace: 'devonline.plugin.grid',
        defaults: {
            remember: false,
            type: 'grid',
            side: 'server',
            role: "kendoGrid",
            url: undefined,
            related: undefined,
            dataField: undefined,               //指定如果使用客户端数据的话, 取上层或关联 form 对象的那个字段的数据, 默认取关联对象的 data 值
            dataStateField: 'State',            //当前表格绑定的对象的数据状态字段
            dataSource: {},
            columns: [],
            filters: [],
            pageable: {},
            data: [],

            loading: undefined,
            loaded: undefined,
            changing: undefined,
            changed: undefined,
            clicking: undefined,
            clicked: undefined,
            dblclicking: undefined,
            dblclicked: undefined,
            binding: undefined,
            bound: undefined
        },
        initials: {
            role: 'kendoGrid',
            //height: 405,
            tableHeight: 330,
            tableHeightIE: 346,
            tableHeights: [330, 660, 990],
            allowCopy: true,
            selectable: true,
            filterable: false,
            sortable: true,
            resizable: true,
            scrollable: true,
            rowIndex: true,                     //是否启用rowIndex显示, 如启用, 可传入 rowIndex 值, 作为显示位置, 如 rowIndex: 1, 显示为第二列
            columnMenu: true,
            dataSource: this.dataSource.grid,
            pageable: {
                refresh: true,
                //pageSizes: [10, 20, 30, 50, 100, 'All'],
                pageSizes: [10, 20, 30, 50, 100],
                pageSize: 10,
                buttonCount: 10
            }
        },
        methods: [
            'init',
            'resize',
            'getData',
            'getValue',
            'setValue',
            'query',
            'select',
            'refresh',
            'destroy'
        ],
        events: [
            'change',
            'click',
            'dblclick'
        ],
        rowIndex: {
            field: '_RowIndex',
            title: '序号',
            width: 48,
            menu: false,
            template: function (e) {
                if ($.com.hasValue(e)) {
                    return e._RowIndex;
                }
            }
        }
    };

    this.popupWindow = {
        namespace: 'devonline.plugin.popupWindow',
        // parameter 数据结构 {transfer: 'in', source: 'Code', target: 'Name', value: '123'} 数组, transfer 默认 out
        // 简单模式: Name 即将 Name 列绑定到 target 属性, transfer 默认 out ,  source 默认当前绑定属性(field), value 默认当前绑定属性值
        // 完全模式: [{transfer: 'in', source: 'Code', target: 'Name', value: '123'}, {transfer: 'out', source: 'Code', target: 'Name', value: '123'}]
        defaults: {
            role: 'kendoWindow',
            popup: undefined,
            type: undefined,
            form: undefined,
            data: undefined,
            opener: undefined,
            parameter: undefined,
            loading: undefined,
            loaded: undefined,
            opening: undefined,
            opened: undefined,
            confirming: undefined,
            confirmed: undefined,
            closing: undefined,
            closed: undefined
        },
        initials: {
            modal: true,
            pinned: false,
            iframe: false,
            autoFocus: true,
            visible: false,
            resizable: false,
            draggable: true,
            scrollable: true,
            isGrid: true,
            isMultiple: false,
            multiple: 'row',
            size: 'default',
            minWidth: 320,
            minHeight: 180,
            actions: [
                "Minimize",
                "Maximize",
                "Close"
            ]
        },
        methods: [
            'init',
            'select',
            'getData',
            'getValue',
            'setValue',
            'destroy'
        ],
        events: [
            'open',
            'close',
            'ok',
            'dblclick',
            'query'
        ],
        //尺寸设定默认比例: 16:9
        size: {
            //默认的弹出页面, medium 中号的 (50倍)
            'default': {
                width: '800',
                height: '450'
            },
            //UHD 尺寸的, 4K 寸尺显示的, 信息量极大的页面 (240倍)
            uhd: {
                width: '3840',
                height: '2160'
            },
            //WQHD 尺寸的, 2K 寸尺显示的, 信息量超大的页面 (160倍)
            wqhd: {
                width: '2560',
                height: '1440'
            },
            //FHD 尺寸的, 超大号的, 信息量很大的页面 (120倍)
            fhd: {
                width: '1920',
                height: '1080'
            },
            //HD 尺寸的, 超大号的, 信息量大的页面 (80倍)
            hd: {
                width: '1280',
                height: '720'
            },
            //大号的, 信息量较大的页面 (60倍)
            large: {
                width: '960',
                height: '540'
            },
            //中号的, 尺寸同 default, 显示一般信息量的常规内容 (50倍)
            medium: {
                width: '800',
                height: '450'
            },
            //小号的, 字段不多的小页面 (40倍)
            small: {
                width: '640',
                height: '360'
            },
            //最小页面（比如：提示页面）(20倍)
            mini: {
                width: '320',
                height: '180'
            }
        }
    };

    /*
    *   popupParameter 属性, 有以下属性
    *   opener: undefined,                                  //打开者 / 接收者, 默认取当前组件所在form;
    *   openerProperty: undefined,                          //指示接收者接收的属性;
    *   inout: []                                           //这个参数是原来 parameter 参数的简写形式, 由左侧 in 属性名 = 右侧 out 属性名/值来构成; 如果无此参数, 则默认用当前元素构造出来
    */
    this.popup = {
        namespace: 'devonline.plugin.popup',
        defaults: {
            popup: undefined,
            popupParameter: undefined,
            role: undefined,                                //*****组件可用性级别, 分以下4种, 但是如果组件属性跟role定义的组件属性冲突, 优先以role定义为主: 
            enable: true,                                   //enable: 可用(可编辑, 可触发事件, 反之均不能)
            editable: false,                                //editable: 可编辑(指可输入或选择, 但不可触发事件)
            readonly: true,                                 //readonly: 只读(不可编辑, 但可触发事件)
            display: true                                   //display: 可见(不可见状态不能人为触发事件, 仅能通过脚本触发)
        },
        methods: [
            'init',
            'getData',
            'getValue',
            'setValue'
        ],
        events: ['open']
    };

    this.showbox = {
        namespace: 'devonline.plugin.showbox',
        defaults: {
            showbox: undefined,
            showboxParameter: undefined,
            template: '#__TemplateShowBox',
            tagTemplate: '#__TemplateTag',
            showField: undefined,
            button: 'showbox',
            clicking: undefined,
            clicked: undefined,
        },
        methods: [
            'init',
            'getData',
            'getValue',
            'setValue'
        ],
        events: ['click']
    };

    this.alert = {
        namespace: 'devonline.plugin.alert',
        defaults: {
            alert: undefined,
            autoClose: false,
            timeout: 3000,
            template: '#__ModalAlertTemplate',

            loading: undefined,
            loaded: undefined,
            opening: undefined,
            opened: undefined,
            confirming: undefined,
            confirmed: undefined,
            closing: undefined,
            closed: undefined,
            cancelling: undefined,
            cancelled: undefined
        },
        methods: [
            'init',
            'getData',
            'getValue',
            'setValue'
        ],
        events: [
            'open',
            'close',
            'ok'
        ]
    };

    this.uploader = {
        initials: {
            enable: true,
            viewable: true,
            editable: false,
            deletable: true,
            multiple: true,
            fieldset: true,
            role: 'kendoUpload',
            type: 'file',
            template: undefined,
            uploadTemplate: '#__TemplateFileAttachment',
            label: undefined,
            title: undefined,
            layout: 'vertical',
            size: '12,12,12',
            fileSize: 10240,                    //文件大小, 单位 KB, 默认 10M
            fileCount: undefined,               //文件数量
            fileExtension: '.pdf, .xlsx, .xls, .docx, .doc, .pptx, .ppt, .jpg, .jpeg, .png, .gif, .bmp, .html, .zip, .rar',   //文件扩展名, 多个扩展名用","隔开, * 指任意文件;  
            async: {
                saveUrl: "/api/Attachments/Upload",
                removeUrl: "/api/Attachments/Delete",
                autoUpload: true,
                removeVerb: "DELETE"
            },
            localization: {
                select: "请选择"
            },
            loading: function (el) {
                if ($.com.hasValue(el) && $.com.isJqueryObject(el.$form)) {
                    var formData = el.getFormData();
                    if ($.com.hasValue(formData)) {
                        var files = [];
                        var attachments = formData[el.options.withAttachments];
                        if ($.com.isArray(attachments)) {
                            for (var i = 0; i < attachments.length; i++) {
                                var attachment = attachments[i];
                                if ($.com.hasValue(attachment)) {
                                    //attachment._fileName = attachment.Name;
                                    //attachment.fileName = attachment.Path;
                                    files.push({
                                        name: attachment.Name,
                                        size: attachment.Length,
                                        path: attachment.Path,
                                        extension: attachment.Extension
                                    });
                                }
                            }
                        }

                        el.initials.files = files;
                    }
                }
            },
            loaded: function (el) {
                var $uploader = el.$el.closest('.k-upload');
                if ($uploader.hasValue()) {
                    var $uploadFiles = $uploader.find('.k-upload-files');
                    var $dropzone = $uploader.find('.k-dropzone');
                    if ($uploadFiles.hasValue() && $dropzone.hasValue() && el.options.enable) {
                        $uploadFiles.insertBefore($dropzone);
                    } else {
                        if (!el.options.enable) {
                            $dropzone.remove();

                            if (!$uploadFiles.hasValue()) {
                                //$uploader.append('<span data-field="_UploadFile">无附件</span>');
                                $uploader.append('<span style="color:#336199;font-weight: 400;">无附件</span>');
                            }
                        }
                    }

                    var $buttons = $uploader.find('.k-upload-files .k-file-success .k-upload-status');
                    if ($buttons.hasValue() && $.com.isArray(el.initials.files)) {
                        $buttons.each(function () {
                            var $this = $(this);
                            $this.children().eq(0).hide();
                            //$this.children().eq(1).append('<span class="k-icon ion-eye" data-button="download" data-file-name="' + $this.attr('data-path') + '" data-file-name="' + $this.prev().attr('title') + '" title="查看" aria-label="查看"></span>').hide();
                            //$this.children().eq(2).append('<span class="k-icon ion-edit" title="编辑" aria-label="编辑"></span>').hide();

                            if (el.options.deletable) {
                                $this.children().eq(0).show();
                            }
                            //if (el.options.viewable) {
                            //    $this.children().eq(1).show().children().button();
                            //}
                            //if (el.options.editable) {
                            //    $this.children().eq(2).show();
                            //}

                            //$this.children().eq(0).insertAfter($this.children().eq(2));
                        });
                    }
                }
            },
            selected: function (el, e) {
                if ($.com.hasValue(el.options) && $.com.hasValue(e) && $.com.isArray(e.files)) {
                    var valid = $.com.hasValue(el.role);
                    var formData = el.getFormData();
                    if (valid && $.com.hasValue(formData)) {
                        var attachments = formData[el.options.withAttachments] || [];
                        if ($.isArray(attachments)) {
                            //移除重复文件
                            if ($.com.isArray(attachments)) {
                                for (var i = 0; i < e.files.length; i++) {
                                    var name = e.files[i].name;
                                    if (attachments.exist(x => x.Name === name)) {
                                        e.files.splice(i, 1);
                                    }
                                }
                            }

                            //移除超出文件
                            if ($.com.hasValue(el.options.fileCount) && (e.files.length + attachments.length > el.options.fileCount)) {
                                app.warning('只能上传 ' + el.options.fileCount + ' 个文件!');
                                while (e.files.length + attachments.length > el.options.fileCount) {
                                    e.files.splice(e.files.length - 1, 1);
                                }
                            }

                            if ($.com.isArray(e.files)) {
                                //验证文件类型
                                if (el.options.fileExtension !== '*') {
                                    var exts = el.options.fileExtension + ',';
                                    if (!e.files.exist(x => exts.includes(x.extension.toLowerCase() + ','))) {
                                        valid = false;
                                        app.warning('只能上传 ' + el.options.fileExtension + ' 类型的文件!');
                                    }
                                }

                                //验证文件大小
                                if (valid && e.files.exist(x => x.size > el.options.fileSize * 1024)) {
                                    valid = false;

                                    var size = el.initials.fileSize;
                                    if ((size / 1024) >= 1) {
                                        size = $.com.toFixed(size / 1024, 2) + 'MB';
                                    } else {
                                        size = size + 'KB';
                                    }

                                    app.warning('单个文件不能超过 ' + size + ' 大小!');
                                }
                            }
                        }
                    }

                    if (!valid) {
                        while (e.files.length > 0) {
                            e.files.splice(0, 1);
                        }
                    }
                }
            },
            remove: function (e) {
                if ($.com.hasValue(e) && $.com.isArray(e.files) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element)) {
                    var $field = e.sender.element;
                    var files = e.files;
                    var $form = $field.closest(that.selector.form);
                    if ($.com.isJqueryObject($form)) {
                        var formData = $.com.getFormData($form);
                        if ($.com.hasValue(formData)) {
                            var attachments = formData[e.sender.options.withAttachments];
                            if ($.com.isArray(attachments)) {
                                var field = $field.data(_config_.field.namespace);
                                if ($.com.hasValue(field)) {
                                    for (var i = 0; i < files.length; i++) {
                                        var file = files[i];
                                        var attachment = attachments.first(x => x.Path === file.Path);
                                        if (!$.com.hasValue(attachment)) {
                                            attachment = attachments.first(x => x.Name === file.Name || x.Name === file.name);
                                            file.Name = attachment.Path;
                                            file.Path = attachment.Path;
                                        }

                                        if ($.com.hasValue(attachment)) {
                                            attachments.remove(attachment, 'Path');
                                            if ($.com.hasValue(field.role) && $.com.hasValue(file.uid) && typeof field.role.removeFileByUid === 'function') {
                                                field.role._removeFileByUid(file.uid, false);
                                            }
                                        }
                                    }

                                    formData[e.sender.options.withAttachments] = attachments;
                                }

                                //remove 将不执行服务器删除方法, 删除附件在客户端提交后, 有服务器完成
                                e.preventDefault();
                            }
                        }
                    }
                }
            },
            upload: function (e) {
                if ($.com.hasValue(e) && $.com.isArray(e.files) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element)) {
                    //由于kendoUpload组件上传时移除了组件数据, 此处需重新修正组件数据引用
                    var $field = e.sender.element;
                    var field = this[that.field.namespace];
                    if ($.com.isJqueryObject($field) && $.com.hasValue(field)) {
                        field.execute(field.options.recalculate);
                        var form = field.$form.data(that.form.namespace);
                        if ($.com.hasValue(form)) {
                            var attachments = form.options.data[e.sender.options.withAttachments];
                            if ($.com.isArray(attachments)) {
                                if (attachments.exist(function (x) { return x.Name === e.files[0].name; })) {
                                    e.preventDefault();
                                }
                            }
                        } else {
                            e.files.splice(0, 1);
                            e.preventDefault();
                        }
                    }
                }
            },
            success: function (e) {
                //成功后会执行此方法
                //TODO 多文件上传暂未验证
                if ($.com.hasValue(e) && $.com.hasValue(e.response) && $.com.isArray(e.response) && e.response[0].StatusCode.toLowerCase() === 'ok' && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var file = e.response[0];
                    var $uploader = e.sender.wrapper;
                    var $uploadFiles = $uploader.find('.k-upload-files');
                    if ($uploadFiles.prev().hasValue()) {
                        $uploadFiles.insertBefore($uploadFiles.prev());
                    }

                    $uploader.find('.k-file-progress .file-icon').attr('src', $.com.getAttachmentFileName(file.FileName, file.Result));
                    $uploader.find('.k-file-progress .k-upload-status').attr('data-path', file.Result);
                    $uploader.find('.k-file-progress .k-upload-status').attr('data-file-name', file.FileName);

                    var $field = e.sender.element;
                    var field = this[that.field.namespace];
                    if ($.com.isJqueryObject($field) && $.com.hasValue(field)) {
                        var formData = field.getFormData();
                        if ($.com.hasValue(formData)) {
                            var attachments = formData[e.sender.options.withAttachments];
                            if (!$.com.isArray(attachments)) {
                                attachments = [];
                            }

                            attachments.push(file.Attachment);
                            field.options.value = attachments;
                            formData[e.sender.options.withAttachments] = attachments;
                        }
                    }
                }
            },
            error: function (e) {
                //失败后会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var $uploader = e.sender.wrapper;
                    var $uploadFiles = $uploader.find('.k-upload-files');
                    if ($uploadFiles.prev().hasValue()) {
                        $uploadFiles.insertBefore($uploadFiles.prev());
                    }
                }
            },
            complete: function (e) {
                //成功失败最终都会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.wrapper) && $.com.hasValue(e.sender.options)) {
                    var $uploader = e.sender.wrapper;
                    var $success = $uploader.find('.k-upload-files .k-file-success');
                    if ($success.hasValue()) {
                        $success = $success.filter(function (i, x) {
                            return !$(x).find('.k-progress').is(':hidden');
                        });
                        if ($success.hasValue()) {
                            $success.each(function () {
                                var $this = $(this);
                                var $status = $this.find('.k-upload-status');
                                var $buttons = $this.find('.k-upload-status button');
                                if ($status.hasValue() && $buttons.hasValue() && $buttons.children().length !== 3) {
                                    $buttons.eq(0).hide();
                                    //$buttons.eq(1).append('<span class="k-icon ion-eye" data-button="download" data-path="' + $status.attr('data-path') + '" data-file-name="' + $status.attr('data-path') + '" title="查看" aria-label="查看"></span>').hide();
                                    //$buttons.eq(2).append('<span class="k-icon ion-edit" title="编辑" aria-label="编辑"></span>').hide();
                                    //$buttons.eq(0).insertAfter($buttons.eq(2));
                                    if (e.sender.options.deletable) {
                                        $buttons.eq(0).show();
                                    }
                                    //if (e.sender.options.viewable) {
                                    //    $buttons.eq(1).show().children().button();
                                    //}
                                    //if (e.sender.options.editable) {
                                    //    $buttons.eq(2).show();
                                    //}
                                }
                            });
                        }
                    }
                }
            },
            recalculate: function (el) {
                //由于kendoUpload组件上传时移除了组件数据, 此处需重新修正组件数据引用
                if ($.com.hasValue(el) && $.com.isJqueryObject(el.$fieldset)) {
                    var $field = el.$fieldset.find('#' + el.options.id);
                    if ($.com.isJqueryObject($field)) {
                        el.$el = $field;
                        el.validator.element = $field;
                        $field.data(that.field.namespace, el);
                        var form = el.$form.data(that.form.namespace);
                        if ($.com.hasValue(form)) {
                            var $el = form.$fields.filter('[data-field="' + el.options.field + '"]');
                            if ($.com.isJqueryObject($el)) {
                                var index = form.$fields.getIndex($el);
                                form.$fields.splice(index, 1, $field[0]);
                            }
                        }
                    }
                }
            }
        },
        single: {
            enable: true,
            viewable: true,
            editable: false,
            deletable: true,
            multiple: false,
            fieldset: true,
            role: 'kendoUpload',
            type: 'file',
            template: undefined,
            uploadTemplate: '#__TemplateFileAttachment',
            label: undefined,
            title: undefined,
            layout: 'horizontal',
            size: '12,3,9',
            fileSize: 10240,                    //文件大小, 单位 KB, 默认 10M
            fileCount: 1,                       //文件数量
            fileExtension: '.pdf, .xlsx, .xls, .docx, .doc, .pptx, .ppt, .jpg, .jpeg, .png, .gif, .bmp, .html, .zip, .rar',   //文件扩展名, 多个扩展名用","隔开, * 指任意文件;  
            async: {
                saveUrl: "/api/Attachments/Upload",
                removeUrl: "/api/Attachments/Delete",
                autoUpload: true,
                removeVerb: "DELETE"
            },
            localization: {
                select: "请选择"
            },
            loading: function (el) {
                if ($.com.hasValue(el) && $.com.isJqueryObject(el.$form)) {
                    var formData = el.getFormData();
                    if ($.com.hasValue(formData)) {
                        var files = [];
                        var attachments = formData[el.options.withAttachments];
                        if ($.com.isArray(attachments)) {
                            for (var i = 0; i < attachments.length; i++) {
                                var attachment = attachments[i];
                                if ($.com.hasValue(attachment)) {
                                    //attachment._fileName = attachment.Name;
                                    //attachment.fileName = attachment.Path;
                                    files.push({
                                        name: attachment.Name,
                                        size: attachment.Length,
                                        path: attachment.Path,
                                        extension: attachment.Extension
                                    });
                                }
                            }
                        }

                        el.initials.files = files;
                    }
                }
            },
            loaded: function (el) {
                var $uploader = el.$el.closest('.k-upload');
                if ($uploader.hasValue()) {
                    var $uploadFiles = $uploader.find('.k-upload-files');
                    var $dropzone = $uploader.find('.k-dropzone');
                    if ($dropzone.hasValue()) {
                        if ($uploadFiles.hasValue() && el.options.enable) {
                            $uploadFiles.insertBefore($dropzone);
                            $dropzone.hide();
                        } else {
                            if (!el.options.enable) {
                                $dropzone.remove();

                                if (!$uploadFiles.hasValue()) {
                                    //$uploader.append('<span data-field="_UploadFile">无附件</span>');
                                    $uploader.append('<span style="color:#336199;font-weight: 400;">无附件</span>');
                                }
                            } else {
                                $dropzone.show();
                            }
                        }
                    }

                    var $buttons = $uploader.find('.k-upload-files .k-file-success .k-upload-status');
                    if ($buttons.hasValue() && $.com.isArray(el.initials.files)) {
                        $buttons.each(function () {
                            var $this = $(this);
                            $this.children().eq(0).hide();
                            //$this.children().eq(1).append('<span class="k-icon ion-eye" data-button="download" data-file-name="' + $this.attr('data-path') + '" data-file-name="' + $this.prev().attr('title') + '" title="查看" aria-label="查看"></span>').hide();
                            //$this.children().eq(2).append('<span class="k-icon ion-edit" title="编辑" aria-label="编辑"></span>').hide();

                            if (el.options.deletable) {
                                $this.children().eq(0).show();
                            }
                            //if (el.options.viewable) {
                            //    $this.children().eq(1).show().children().button();
                            //}
                            //if (el.options.editable) {
                            //    $this.children().eq(2).show();
                            //}

                            //$this.children().eq(0).insertAfter($this.children().eq(2));
                        });
                    }
                }
            },
            selected: function (el, e) {
                if ($.com.hasValue(el.options) && $.com.hasValue(e) && $.com.isArray(e.files)) {
                    var valid = $.com.hasValue(el.role);
                    var formData = el.getFormData();
                    if (valid && $.com.hasValue(formData)) {
                        var attachments = formData[el.options.withAttachments] || [];
                        if ($.com.isArray(attachments)) {
                            //文件不能重名
                            let attachment = attachments.first(x => x.BusinessType === el.options.businessType);
                            if (!attachment) {
                                valid = e.files.exist(x => x.name === attachment.Name);
                            }

                            //移除超出文件
                            if (e.files.length + attachments.length > 1) {
                                app.warning('只能上传 1 个文件!');
                                valid = false;
                            }

                            if ($.com.isArray(e.files)) {
                                //验证文件类型
                                if (el.options.fileExtension !== '*') {
                                    var exts = el.options.fileExtension + ',';
                                    if (!e.files.exist(x => exts.includes(x.extension.toLowerCase() + ','))) {
                                        valid = false;
                                        app.warning('只能上传 ' + el.options.fileExtension + ' 类型的文件!');
                                    }
                                }

                                //验证文件大小
                                if (valid && e.files.exist(x => x.size > el.options.fileSize * 1024)) {
                                    valid = false;

                                    var size = el.initials.fileSize;
                                    if ((size / 1024) >= 1) {
                                        size = $.com.toFixed(size / 1024, 2) + 'MB';
                                    } else {
                                        size = size + 'KB';
                                    }

                                    app.warning('单个文件不能超过 ' + size + ' 大小!');
                                }
                            }
                        }
                    }

                    if (!valid) {
                        while (e.files.length > 0) {
                            e.files.splice(0, 1);
                        }
                    }
                }
            },
            remove: function (e) {
                if ($.com.hasValue(e) && $.com.isArray(e.files) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element)) {
                    e.sender.wrapper.find('.k-dropzone').show();
                    var $field = e.sender.element;
                    var $form = $field.closest(that.selector.form);
                    if ($.com.isJqueryObject($form)) {
                        var formData = $.com.getFormData($form);
                        if ($.com.hasValue(formData)) {
                            var attachments = formData[e.sender.options.withAttachments];
                            if ($.com.isArray(attachments)) {
                                var file = e.files[0];
                                var field = $field.data(_config_.field.namespace);
                                var attachment = attachments.first(x => x.BusinessType === field.options.businessType && x.Name === file.Name);
                                if ($.com.hasValue(attachment)) {
                                    attachments.remove(attachment, 'Path');
                                    formData[e.sender.options.withAttachments] = attachments;
                                }

                                if ($.com.hasValue(field) && $.com.hasValue(field.role) && $.com.hasValue(file.uid) && typeof field.role.removeFileByUid === 'function') {
                                    field.role._removeFileByUid(file.uid, false);
                                }

                                //remove 将不执行服务器删除方法, 删除附件在客户端提交后, 有服务器完成
                                e.preventDefault();
                            }
                        }
                    }
                }
            },
            upload: function (e) {
                if ($.com.hasValue(e) && $.com.isArray(e.files) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element)) {
                    //由于kendoUpload组件上传时移除了组件数据, 此处需重新修正组件数据引用
                    var $field = e.sender.element;
                    var field = this[that.field.namespace];
                    if ($.com.isJqueryObject($field) && $.com.hasValue(field)) {
                        e.sender.wrapper.find('.k-dropzone').hide();
                        field.execute(field.options.recalculate);
                        var form = field.$form.data(that.form.namespace);
                        if ($.com.hasValue(form)) {
                            var attachments = form.options.data[e.sender.options.withAttachments];
                            if ($.com.isArray(attachments)) {
                                if (attachments.exist(function (x) { return x.Name === e.files[0].name; })) {
                                    e.preventDefault();
                                }
                            }
                        } else {
                            e.files.splice(0, 1);
                            e.preventDefault();
                        }
                    }
                }
            },
            success: function (e) {
                //成功后会执行此方法
                //TODO 多文件上传暂未验证
                if ($.com.hasValue(e) && $.com.hasValue(e.response) && $.com.isArray(e.response) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var file = e.response[0];
                    if ((file.StatusCode.toLowerCase() === 'ok' || file.StatusCode === 200) && $.com.hasValue(file.Attachment)) {
                        var $uploader = e.sender.wrapper;
                        var $uploadFiles = $uploader.find('.k-upload-files');
                        if ($uploadFiles.prev().hasValue()) {
                            $uploadFiles.insertBefore($uploadFiles.prev());
                        }

                        $uploader.find('.k-file-progress .file-icon').attr('src', $.com.getAttachmentFileName(file.FileName, file.Result));
                        $uploader.find('.k-file-progress .k-upload-status').attr('data-path', file.Result);
                        $uploader.find('.k-file-progress .k-upload-status').attr('data-file-name', file.FileName);

                        var $field = e.sender.element;
                        var field = $field.data(_config_.field.namespace);
                        if ($.com.isJqueryObject($field) && $.com.hasValue(field)) {
                            let attachment = file.Attachment;
                            var formData = field.getFormData();
                            if ($.com.hasValue(formData)) {
                                attachment.BusinessType = field.options.businessType;
                                var attachments = formData[field.options.withAttachments];
                                if (!$.com.isArray(attachments)) {
                                    attachments = [];
                                }

                                attachments.push(file.Attachment);
                                field.options.value = attachment.Path;
                                formData[field.options.withAttachments] = attachments;
                            }
                        }
                    }
                }
            },
            error: function (e) {
                //失败后会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var $uploader = e.sender.wrapper;
                    var $uploadFiles = $uploader.find('.k-upload-files');
                    if ($uploadFiles.prev().hasValue()) {
                        $uploadFiles.insertBefore($uploadFiles.prev());
                    }
                }
            },
            complete: function (e) {
                //成功失败最终都会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.wrapper) && $.com.hasValue(e.sender.options)) {
                    var $uploader = e.sender.wrapper;
                    var $success = $uploader.find('.k-upload-files .k-file-success');
                    if ($success.hasValue()) {
                        $success = $success.filter(function (i, x) {
                            return !$(x).find('.k-progress').is(':hidden');
                        });
                        if ($success.hasValue()) {
                            $success.each(function () {
                                var $this = $(this);
                                var $status = $this.find('.k-upload-status');
                                var $buttons = $this.find('.k-upload-status button');
                                if ($status.hasValue() && $buttons.hasValue() && $buttons.children().length !== 3) {
                                    $buttons.eq(0).hide();
                                    //$buttons.eq(1).append('<span class="k-icon ion-eye" data-button="download" data-path="' + $status.attr('data-path') + '" data-file-name="' + $status.attr('data-path') + '" title="查看" aria-label="查看"></span>').hide();
                                    //$buttons.eq(2).append('<span class="k-icon ion-edit" title="编辑" aria-label="编辑"></span>').hide();
                                    //$buttons.eq(0).insertAfter($buttons.eq(2));
                                    if (e.sender.options.deletable) {
                                        $buttons.eq(0).show();
                                    }
                                    //if (e.sender.options.viewable) {
                                    //    $buttons.eq(1).show().children().button();
                                    //}
                                    //if (e.sender.options.editable) {
                                    //    $buttons.eq(2).show();
                                    //}
                                }
                            });
                        }
                    }
                }
            },
            recalculate: function (el) {
                //由于kendoUpload组件上传时移除了组件数据, 此处需重新修正组件数据引用
                if ($.com.hasValue(el) && $.com.isJqueryObject(el.$fieldset)) {
                    var $field = el.$fieldset.find('#' + el.options.id);
                    if ($.com.isJqueryObject($field)) {
                        el.$el = $field;
                        el.validator.element = $field;
                        $field.data(that.field.namespace, el);
                        var form = el.$form.data(that.form.namespace);
                        if ($.com.hasValue(form)) {
                            var $el = form.$fields.filter('[data-field="' + el.options.field + '"]');
                            if ($.com.isJqueryObject($el)) {
                                var index = form.$fields.getIndex($el);
                                form.$fields.splice(index, 1, $field[0]);
                            }
                        }
                    }
                }
            }
        },
        'import': {
            enable: true,
            viewable: false,
            editable: false,
            deletable: false,
            multiple: false,
            fieldset: false,
            role: 'kendoUpload',
            type: 'file',
            template: undefined,
            uploadTemplate: undefined,
            size: '3,12,12',
            fileSize: 20000,                    //文件大小, 单位 KB
            fileCount: 1,                       //文件数量
            fileExtension: '.xlsx',             //文件扩展名, * 指任意文件, 不指定扩展名; 多个扩展名用 , 隔开 
            async: {
                saveUrl: "/api/Attachments/Upload",
                autoUpload: true
            },
            localization: {
                select: "导入"
            },
            selected: function (el, e) {
                if ($.com.hasValue(el.options) && $.com.hasValue(e) && $.com.isArray(e.files)) {
                    if (e.files.length === 1) {
                        var file = e.files[0];
                        var exts = el.options.fileExtension.split(',');
                        if (!exts.exist(function (x) { return x === file.extension.toLowerCase(); })) {
                            e.files.splice(0, 1);
                            //$.com.WarningDialog('只能导入 ' + el.options.fileExtension + ' 类型的文件!');
                            app.warning('只能导入 ' + el.options.fileExtension + ' 类型的文件!');
                        }

                        if (file.size > el.options.fileSize * 1024) {
                            e.files.splice(0, 1);
                            //$.com.WarningDialog('只能导入不超过 ' + el.options.fileSize + 'KB 大小的文件!');
                            app.warning('只能导入不超过 ' + el.options.fileSize + 'KB 大小的文件!');
                        }
                    } else {
                        while (e.files.length > 0) {
                            e.files.splice(0, 1);
                        }

                        //$.com.WarningDialog('每次只能导入一个文件!');
                        app.warning('每次只能导入一个文件!');
                    }
                }
            },
            success: function (e) {
                //成功后会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.response) && $.com.isArray(e.response) && e.response.length === 1 && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.element) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var fileName = e.response[0].result;
                    var $uploader = e.sender.wrapper;
                    var $button = $uploader.closest('[data-button="import"]');
                    if ($button.hasValue()) {
                        $button.button('setValue', 'options.fileName', fileName);
                        $button.click();
                    }
                }
            },
            complete: function (e) {
                //成功失败最终都会执行此方法
                if ($.com.hasValue(e) && $.com.hasValue(e.sender) && $.com.isJqueryObject(e.sender.wrapper)) {
                    var $uploader = e.sender.wrapper;
                    $uploader.find('.k-upload-files').remove();
                    var $button = $uploader.closest('[data-button="import"]');
                    if ($button.hasValue()) {
                        $button.button('setValue', 'options.fileName', null);
                    }
                }
            }
        }
    };

    this.validator = {
        defaults: {
            validateOnBlur: false,
            //errorTemplate: '<span class="' + that.attribute.inputInvalidMsg + '">#=message#</span>'
        },
        requiredDisplay: {
            rules: {
                requiredDisplay: function ($el) {
                    var field = $el.data(that.field.namespace);
                    if ($.com.hasValue(field)) {
                        return field.options.display === false || (field.options.display && $.com.hasValue($el.val()));
                    }

                    return $el.is(':hidden') || (!$el.is(':hidden') && $.com.hasValue($el.val()));
                }
            },
            messages: {
                requiredDisplay: function ($el) {
                    return $el.attr('name') + ' 为必填项';
                }
            }
        },
        maxLength: {
            rules: {
                maxLength: function ($el) {
                    if ($el.is(that.selector.maxLength)) {
                        return $el.val().length <= Number($el.attr(that.attribute.maxLength) || 0);
                    }

                    return true;
                }
            },
            messages: {
                maxLength: function ($el) {
                    return $el.attr('name') + ' 最多可以输入 ' + $el.attr(that.attribute.maxLength) + ' 个字符!';
                }
            }
        },
        minLength: {
            rules: {
                minLength: function ($el) {
                    if ($el.is(that.selector.minLength)) {
                        return $el.val().length >= Number($el.attr(that.attribute.minLength) || 0);
                    }

                    return true;
                }
            },
            messages: {
                minLength: function ($el) {
                    return $el.attr('name') + ' 必须至少输入 ' + $el.attr(that.attribute.minLength) + ' 个字符';
                }
            }
        },
        groupRequired: {
            rules: {
                required: function ($el) {
                    var el;
                    if (!$el.is(that.selector.field)) {
                        el = $el.parents(that.selector.field).first();
                        if (el.hasValue()) {
                            el = el.data(that.field.namespace);
                        }
                    } else {
                        el = $el.data(that.field.namespace);
                    }

                    if ($.com.hasValue(el) && $.com.hasValue(el.options) && el.options.withGroup && (el.options.role === 'checkbox' || el.options.role === 'radio')) {
                        return $.com.hasValue(el.options.value);
                    }

                    return true;
                }
            },
            messages: {
                required: function ($el) {
                    return $el.parents(that.selector.field).attr('name') + ' 必须至少选择其中一项';
                }
            }
        },
        attachmentRequired: {
            rules: {
                required: function ($el) {
                    var result = $.com.isJqueryObject($el) && $el[0].files.length > 0;
                    if (!result) {
                        var field = $el.data(that.field.namespace);
                        if ($.com.hasValue(field)) {
                            var data = $.com.getFormData(field.$form);
                            result = $.com.hasValue(data) && $.com.hasValue(field.options.field) && $.com.isArray(data[field.options.field]);
                        }
                    }

                    return result;
                }
            },
            messages: {
                required: function ($el) {
                    var name = "附件";
                    var field = $el.data(that.field.namespace);
                    if ($.com.hasValue(field) && $.com.hasValue(field.options.name)) {
                        name = field.options.name;
                    }

                    return name + " 为必填项";
                }
            }
        }
    };

    this.format = {
        'default': {
            timezone: 'Asia/Shanghai',
            date: 'yyyy-MM-dd',
            time: 'HH:mm:ss',
            datetime: 'yyyy-MM-dd HH:mm:ss'
        },
        'monemt': {
            date: 'YYYY-MM-DD',
            time: 'HH:mm:ss',
            datetime: 'YYYY-MM-DD HH:mm:ss'
        },
        grid: {
            date: '{0: yyyy/MM/dd}',
            time: '{0: HH:mm:ss}',
            datetime: '{0: yyyy/MM/dd HH:mm:ss}'
        },
    };
};